//// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
//package com.linqingying.gitcode.pullrequest.ui.toolwindow.create
//
//import com.intellij.CommonBundle
//import com.intellij.collaboration.async.CompletableFutureUtil.successOnEdt
//import com.intellij.collaboration.ui.*
//import com.intellij.collaboration.util.CollectionDelta
//import com.intellij.icons.AllIcons
//import com.intellij.ide.BrowserUtil
//import com.intellij.openapi.progress.ProgressIndicator
//import com.intellij.openapi.progress.util.ProgressWrapper
//import com.intellij.openapi.project.Project
//import com.intellij.openapi.ui.Messages
//import com.intellij.openapi.util.NlsActions
//import com.intellij.openapi.util.text.HtmlBuilder
//import com.intellij.ui.AnimatedIcon
//import com.intellij.ui.HyperlinkAdapter
//import com.intellij.ui.IdeBorderFactory
//import com.intellij.ui.SideBorder
//import com.intellij.ui.components.JBOptionButton
//import com.intellij.ui.components.JBScrollPane
//import com.intellij.ui.components.JBTextArea
//import com.intellij.util.ui.JBFont
//import com.intellij.util.ui.JBUI
//import com.intellij.util.ui.UIUtil
//import git4idea.GitLocalBranch
//import git4idea.GitPushUtil
//import git4idea.GitPushUtil.findOrPushRemoteBranch
//import git4idea.GitPushUtil.findPushTarget
//import git4idea.GitRemoteBranch
//import git4idea.ui.branch.MergeDirectionComponentFactory
//import git4idea.ui.branch.MergeDirectionModel
//import net.miginfocom.layout.CC
//import net.miginfocom.layout.LC
//import net.miginfocom.swing.MigLayout
//import org.jetbrains.annotations.Nls
//import com.linqingying.gitcode.api.data.GCLabel
//import com.linqingying.gitcode.api.data.GCUser
//import com.linqingying.gitcode.api.data.pullrequest.GCPullRequestRequestedReviewer
//import com.linqingying.gitcode.api.data.pullrequest.GCPullRequestShort
//import com.linqingying.gitcode.i18n.GitCodeBundle
//import com.linqingying.gitcode.pullrequest.config.GitCodePullRequestsProjectUISettings
//import com.linqingying.gitcode.pullrequest.data.GCPRDataContext
//import com.linqingying.gitcode.pullrequest.data.GCPRIdentifier
//import com.linqingying.gitcode.pullrequest.ui.GCCompletableFutureLoadingModel
//import com.linqingying.gitcode.pullrequest.ui.GCIOExecutorLoadingModel
//import com.linqingying.gitcode.pullrequest.ui.GCLoadingModel
//import com.linqingying.gitcode.pullrequest.ui.GCSimpleLoadingModel
//import com.linqingying.gitcode.pullrequest.ui.details.GCPRMetadataPanelFactory
//import com.linqingying.gitcode.pullrequest.ui.toolwindow.GCPRToolWindowTab
//import com.linqingying.gitcode.pullrequest.ui.toolwindow.model.GCPRToolWindowProjectViewModel
//import com.linqingying.gitcode.ui.util.DisableableDocument
//import com.linqingying.gitcode.util.GCGitRepositoryMapping
//import java.awt.Component
//import java.awt.Container
//import java.awt.event.ActionEvent
//import java.util.concurrent.CompletableFuture
//import javax.swing.*
//import javax.swing.event.HyperlinkEvent
//import javax.swing.text.Document
//
//internal class GCPRCreateInfoComponentFactory(private val project: Project,
//                                              private val settings: GitCodePullRequestsProjectUISettings,
//                                              private val dataContext: GCPRDataContext,
//                                              private val projectVm: GCPRToolWindowProjectViewModel) {
//
//  fun create(directionModel: MergeDirectionModel<GCGitRepositoryMapping>,
//             titleDocument: Document,
//             descriptionDocument: DisableableDocument,
//             metadataModel: GCPRCreateMetadataModel,
//             commitsCountModel: SingleValueModel<Int?>,
//             existenceCheckLoadingModel: GCIOExecutorLoadingModel<GCPRIdentifier?>,
//             createLoadingModel: GCCompletableFutureLoadingModel<GCPullRequestShort>): JComponent {
//
//    val progressIndicator = ListenableProgressIndicator()
//    val existenceCheckProgressIndicator = ListenableProgressIndicator()
//    val createAction = CreateAction(directionModel, titleDocument, descriptionDocument, metadataModel, false, createLoadingModel,
//                                    progressIndicator, GitCodeBundle.message("pull.request.create.action"))
//    val createDraftAction = CreateAction(directionModel, titleDocument, descriptionDocument, metadataModel, true, createLoadingModel,
//                                         progressIndicator, GitCodeBundle.message("pull.request.create.draft.action"))
//    val cancelAction = object : AbstractAction(CommonBundle.getCancelButtonText()) {
//      override fun actionPerformed(e: ActionEvent?) {
//        val discard = Messages.showYesNoDialog(project,
//                                               GitCodeBundle.message("pull.request.create.discard.message"),
//                                               GitCodeBundle.message("pull.request.create.discard.title"),
//                                               GitCodeBundle.message("pull.request.create.discard.approve"),
//                                               CommonBundle.getCancelButtonText(), Messages.getWarningIcon())
//        if (discard == Messages.NO) return
//
//        progressIndicator.cancel()
//        projectVm.closeTab(GCPRToolWindowTab.NewPullRequest)
//        createLoadingModel.future = null
//        existenceCheckLoadingModel.reset()
//      }
//    }
//    InfoController(directionModel, existenceCheckLoadingModel, existenceCheckProgressIndicator, createAction, createDraftAction)
//
//    val directionSelector = MergeDirectionComponentFactory(
//      directionModel,
//      { model ->
//        with(model) {
//          val branch = baseBranch ?: return@with null
//          val headRepoPath = headRepo?.repository?.repositoryPath
//          val baseRepoPath = baseRepo.repository.repositoryPath
//          val showOwner = headRepoPath != null && baseRepoPath != headRepoPath
//          baseRepo.repository.repositoryPath.toString(showOwner) + ":" + branch.name
//        }
//      },
//
//      { model ->
//        with(model) {
//          val branch = headBranch ?: return@with null
//          val headRepoPath = headRepo?.repository?.repositoryPath ?: return@with null
//          val baseRepoPath = baseRepo.repository.repositoryPath
//          val showOwner = baseRepoPath != headRepoPath
//          headRepoPath.toString(showOwner) + ":" + branch.name
//        }
//      }
//
//    ).create().apply {
//      border = BorderFactory.createCompoundBorder(IdeBorderFactory.createBorder(SideBorder.BOTTOM),
//                                                  JBUI.Borders.empty(7, 8, 8, 8))
//    }
//
//    val titleField = JBTextArea(titleDocument).apply {
//      background = UIUtil.getListBackground()
//      border = BorderFactory.createCompoundBorder(IdeBorderFactory.createBorder(SideBorder.BOTTOM),
//                                                  JBUI.Borders.empty(8))
//      font = JBFont.label()
//      emptyText.text = GitCodeBundle.message("pull.request.create.title")
//      lineWrap = true
//    }.also {
//      CollaborationToolsUIUtil.registerFocusActions(it)
//    }
//
//    val descriptionField = JBTextArea(descriptionDocument).apply {
//      background = UIUtil.getListBackground()
//      border = JBUI.Borders.empty(8, 8, 0, 8)
//      font = JBFont.label()
//      emptyText.text = GitCodeBundle.message("pull.request.create.description")
//      lineWrap = true
//    }.also {
//      CollaborationToolsUIUtil.registerFocusActions(it)
//    }
//    descriptionDocument.addAndInvokeEnabledStateListener {
//      descriptionField.isEnabled = descriptionDocument.enabled
//    }
//
//    val descriptionPane = JBScrollPane(descriptionField,
//                                       ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
//                                       ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER).apply {
//      isOpaque = false
//      border = IdeBorderFactory.createBorder(SideBorder.BOTTOM)
//    }
//
//    val metadataPanel = GCPRMetadataPanelFactory(metadataModel, dataContext.avatarIconsProvider).create().apply {
//      border = BorderFactory.createCompoundBorder(IdeBorderFactory.createBorder(SideBorder.BOTTOM),
//                                                  JBUI.Borders.empty(8))
//    }
//    val createButton = JBOptionButton(createAction, arrayOf(createDraftAction))
//    val cancelButton = JButton(cancelAction)
//    val actionsPanel = HorizontalListPanel(8).apply {
//      add(createButton)
//      add(cancelButton)
//    }
//    val statusPanel = JPanel().apply {
//      layout = MigLayout(LC().gridGap("0", "8").insets("0").fill().flowY().hideMode(3))
//      border = JBUI.Borders.empty(8)
//
//      add(createNoChangesWarningLabel(directionModel, commitsCountModel, createLoadingModel), CC().minWidth("0"))
//      add(createErrorLabel(createLoadingModel, GitCodeBundle.message("pull.request.create.error")), CC().minWidth("0"))
//      add(createErrorLabel(existenceCheckLoadingModel), CC().minWidth("0"))
//      add(createErrorAlreadyExistsLabel(existenceCheckLoadingModel), CC().minWidth("0"))
//      add(createLoadingLabel(existenceCheckLoadingModel, existenceCheckProgressIndicator), CC().minWidth("0"))
//      add(createLoadingLabel(createLoadingModel, progressIndicator), CC().minWidth("0"))
//      add(actionsPanel, CC().minWidth("0"))
//    }
//
//    return JPanel(null).apply {
//      background = UIUtil.getListBackground()
//      layout = MigLayout(LC().gridGap("0", "0").insets("0").fill().flowY())
//      isFocusCycleRoot = true
//      focusTraversalPolicy = object : LayoutFocusTraversalPolicy() {
//        override fun getDefaultComponent(aContainer: Container?): Component {
//          return if (aContainer == this@apply) titleField
//          else super.getDefaultComponent(aContainer)
//        }
//      }
//
//      add(directionSelector, CC().growX().pushX().minWidth("0"))
//      add(titleField, CC().growX().pushX().minWidth("0"))
//      add(descriptionPane, CC().grow().push().minWidth("0"))
//      add(metadataPanel, CC().growX().pushX())
//      add(statusPanel, CC().growX().pushX())
//    }
//  }
//
//  private inner class InfoController(private val directionModel: MergeDirectionModel<GCGitRepositoryMapping>,
//                                     private val existenceCheckLoadingModel: GCIOExecutorLoadingModel<GCPRIdentifier?>,
//                                     private val existenceCheckProgressIndicator: ListenableProgressIndicator,
//                                     private val createAction: AbstractAction,
//                                     private val createDraftAction: AbstractAction) {
//    init {
//      directionModel.addAndInvokeDirectionChangesListener(::update)
//      existenceCheckLoadingModel.addStateChangeListener(object : GCLoadingModel.StateChangeListener {
//        override fun onLoadingCompleted() {
//          update()
//        }
//      })
//      directionModel.addAndInvokeDirectionChangesListener {
//        val baseBranch = directionModel.baseBranch
//        val headRepo = directionModel.headRepo
//        val headBranch = findCurrentRemoteHead(directionModel)
//        if (baseBranch == null || headRepo == null || headBranch == null) existenceCheckLoadingModel.reset()
//        else existenceCheckLoadingModel.load(ProgressWrapper.wrap(existenceCheckProgressIndicator)) {
//          dataContext.creationService.findPullRequest(it, baseBranch, headRepo, headBranch)
//        }
//      }
//      update()
//    }
//
//
//    private fun update() {
//      val enabled = directionModel.let {
//        it.baseBranch != null && it.headRepo != null && it.headBranch != null &&
//        (findCurrentRemoteHead(it) == null || (existenceCheckLoadingModel.resultAvailable && existenceCheckLoadingModel.result == null))
//      }
//      createAction.isEnabled = enabled
//      createDraftAction.isEnabled = enabled
//    }
//
//    private fun findCurrentRemoteHead(directionModel: MergeDirectionModel<GCGitRepositoryMapping>): GitRemoteBranch? {
//      val headRepo = directionModel.headRepo ?: return null
//      val headBranch = directionModel.headBranch ?: return null
//      if (headBranch is GitRemoteBranch) return headBranch
//      else headBranch as GitLocalBranch
//      val gitRemote = headRepo.remote
//      return findPushTarget(gitRemote.repository, gitRemote.remote, headBranch)?.branch
//    }
//  }
//
//  private inner class CreateAction(private val directionModel: MergeDirectionModel<GCGitRepositoryMapping>,
//                                   private val titleDocument: Document, private val descriptionDocument: DisableableDocument,
//                                   private val metadataModel: GCPRCreateMetadataModel,
//                                   private val draft: Boolean,
//                                   private val loadingModel: GCCompletableFutureLoadingModel<GCPullRequestShort>,
//                                   private val progressIndicator: ProgressIndicator,
//                                   @NlsActions.ActionText name: String) : AbstractAction(name) {
//
//    override fun actionPerformed(e: ActionEvent?) {
//      val baseBranch = directionModel.baseBranch ?: return
//      val headRepo = directionModel.headRepo ?: return
//      val headBranch = directionModel.headBranch ?: return
//
//      val reviewers = metadataModel.reviewers
//      val assignees = metadataModel.assignees
//      val labels = metadataModel.labels
//
//      loadingModel.future = if (headBranch is GitRemoteBranch) {
//        CompletableFuture.completedFuture(headBranch)
//      }
//      else {
//        val dialogMessages = GitPushUtil.BranchNameInputDialogMessages(
//          GitCodeBundle.message("pull.request.create.input.remote.branch.title"),
//          GitCodeBundle.message("pull.request.create.input.remote.branch.name"),
//          GitCodeBundle.message("pull.request.create.input.remote.branch.comment")
//        )
//        findOrPushRemoteBranch(project,
//                               progressIndicator,
//                               headRepo.remote.repository,
//                               headRepo.remote.remote,
//                               headBranch as GitLocalBranch,
//                               dialogMessages)
//      }.thenCompose { remoteHeadBranch ->
//        dataContext.creationService
//          .createPullRequest(progressIndicator, baseBranch, headRepo, remoteHeadBranch,
//                             titleDocument.text, descriptionDocument.text, draft)
//          .thenCompose { adjustReviewers(it, reviewers) }
//          .thenCompose { adjustAssignees(it, assignees) }
//          .thenCompose { adjustLabels(it, labels) }
//          .successOnEdt {
//            if (!progressIndicator.isCanceled) {
//              projectVm.closeTab(GCPRToolWindowTab.NewPullRequest)
//              projectVm.viewPullRequest(it.prId)
//              settings.recentNewPullRequestHead = headRepo.repository
//              projectVm.refreshPrOnCurrentBranch()
//            }
//            it
//          }
//      }
//    }
//
//
//    private fun adjustReviewers(pullRequest: GCPullRequestShort, reviewers: List<GCPullRequestRequestedReviewer>)
//      : CompletableFuture<GCPullRequestShort> {
//      return if (reviewers.isNotEmpty()) {
//        dataContext.detailsService.adjustReviewers(ProgressWrapper.wrap(progressIndicator), pullRequest.prId,
//                                                   CollectionDelta(emptyList(), reviewers))
//          .thenApply { pullRequest }
//      }
//      else CompletableFuture.completedFuture(pullRequest)
//    }
//
//    private fun adjustAssignees(pullRequest: GCPullRequestShort, assignees: List<GCUser>)
//      : CompletableFuture<GCPullRequestShort> {
//      return if (assignees.isNotEmpty()) {
//        dataContext.detailsService.adjustAssignees(ProgressWrapper.wrap(progressIndicator), pullRequest.prId,
//                                                   CollectionDelta(emptyList(), assignees))
//          .thenApply { pullRequest }
//      }
//      else CompletableFuture.completedFuture(pullRequest)
//    }
//
//    private fun adjustLabels(pullRequest: GCPullRequestShort, labels: List<GCLabel>)
//      : CompletableFuture<GCPullRequestShort> {
//      return if (labels.isNotEmpty()) {
//        dataContext.detailsService.adjustLabels(ProgressWrapper.wrap(progressIndicator), pullRequest.prId,
//                                                CollectionDelta(emptyList(), labels))
//          .thenApply { pullRequest }
//      }
//      else CompletableFuture.completedFuture(pullRequest)
//    }
//  }
//
//  private fun createErrorAlreadyExistsLabel(loadingModel: GCSimpleLoadingModel<GCPRIdentifier?>): JComponent {
//    val iconLabel = JLabel(AllIcons.Ide.FatalError)
//    val textPane = SimpleHtmlPane(addBrowserListener = false).apply {
//      setHtmlBody(HtmlBuilder()
//                    .append(GitCodeBundle.message("pull.request.create.already.exists"))
//                    .nbsp()
//                    .appendLink("VIEW", GitCodeBundle.message("pull.request.create.already.exists.view"))
//                    .toString())
//      addHyperlinkListener(object : HyperlinkAdapter() {
//        override fun hyperlinkActivated(e: HyperlinkEvent) {
//          if (e.description == "VIEW") {
//            loadingModel.result?.let(projectVm::viewPullRequest)
//          }
//          else {
//            BrowserUtil.browse(e.description)
//          }
//        }
//      })
//    }
//
//    val panel = textPaneWithIcon(iconLabel, textPane)
//
//    fun update() {
//      panel.isVisible = loadingModel.resultAvailable && loadingModel.result != null
//    }
//    loadingModel.addStateChangeListener(object : GCLoadingModel.StateChangeListener {
//      override fun onLoadingStarted() = update()
//      override fun onLoadingCompleted() = update()
//    })
//    update()
//    return panel
//  }
//
//  companion object {
//    private val Document.text: String get() = getText(0, length)
//
//    private fun createNoChangesWarningLabel(directionModel: MergeDirectionModel<GCGitRepositoryMapping>,
//                                            commitsCountModel: SingleValueModel<Int?>,
//                                            loadingModel: GCLoadingModel): JComponent {
//      val iconLabel = JLabel(AllIcons.General.Warning)
//      val textPane = SimpleHtmlPane()
//
//      val panel = textPaneWithIcon(iconLabel, textPane)
//      fun update() {
//        val commits = commitsCountModel.value
//        panel.isVisible = commits == 0 && loadingModel.error == null
//        val base = directionModel.baseBranch?.name.orEmpty()
//        val head = directionModel.headBranch?.name.orEmpty()
//        textPane.text = GitCodeBundle.message("pull.request.create.no.changes", base, head)
//      }
//
//      commitsCountModel.addAndInvokeListener { update() }
//      loadingModel.addStateChangeListener(object : GCLoadingModel.StateChangeListener {
//        override fun onLoadingCompleted() = update()
//      })
//      update()
//      return panel
//    }
//
//    private fun createErrorLabel(loadingModel: GCLoadingModel, @Nls prefix: String? = null): JComponent {
//      val iconLabel = JLabel(AllIcons.Ide.FatalError)
//      val textPane = SimpleHtmlPane()
//
//      val panel = textPaneWithIcon(iconLabel, textPane)
//
//      fun update() {
//        panel.isVisible = loadingModel.error != null
//        textPane.setHtmlBody(prefix?.plus(" ").orEmpty() + loadingModel.error?.message.orEmpty())
//      }
//      loadingModel.addStateChangeListener(object : GCLoadingModel.StateChangeListener {
//        override fun onLoadingStarted() = update()
//        override fun onLoadingCompleted() = update()
//      })
//      update()
//      return panel
//    }
//
//    private fun textPaneWithIcon(iconLabel: JLabel, textPane: JEditorPane) =
//      JPanel(MigLayout(LC().insets("0").gridGap("0", "0"))).apply {
//        add(iconLabel, CC().alignY("top").gapRight("${iconLabel.iconTextGap}"))
//        add(textPane, CC().minWidth("0"))
//      }
//
//    private fun createLoadingLabel(loadingModel: GCLoadingModel, progressIndicator: ListenableProgressIndicator): JLabel {
//      val label = JLabel(AnimatedIcon.Default())
//      fun updateVisible() {
//        label.isVisible = loadingModel.loading
//      }
//      loadingModel.addStateChangeListener(object : GCLoadingModel.StateChangeListener {
//        override fun onLoadingStarted() = updateVisible()
//        override fun onLoadingCompleted() = updateVisible()
//      })
//      updateVisible()
//      progressIndicator.addAndInvokeListener {
//        label.text = progressIndicator.text
//      }
//      return label
//    }
//  }
//}
